/********************************************
 * 功能说明: 
 * 模块名称: 
 * 系统名称: 
 * 软件版权: 北京银杉金服科技有限公司
 * 系统版本: 1.0.0
 * 开发人员: zhangfb
 * 开发时间: 2018/12/18 23:10
 * 审核人员: 
 * 相关文档: 
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.hyacinth.dubbo.registry;

import com.hyacinth.dubbo.constant.Constant;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

/**
 * 服务注册
 * @author zhangfb
 * @version 1.0.0.1
 * @since JDK 1.8
 */
public class ServiceRegistry {

    private static final Logger logger = LoggerFactory.getLogger(ServiceRegistry.class);

    private String registryAddress;

    /*** 线程倒计时，保证当前服务连接高可用 ***/
    private CountDownLatch latch = new CountDownLatch(1);

    public ServiceRegistry(String registryAddress) {
        this.registryAddress = registryAddress;
    }

    /**
     * 注册服务
     * @param serverAddress 服务地址
     */
    public void register(String serverAddress) {
        if (serverAddress != null) {
            ZooKeeper zooKeeper = connectServer();
            if (zooKeeper != null) {
                addRootNode(zooKeeper);
                createNode(zooKeeper, serverAddress);
            }
        }
    }

    /**
     * 获取zookeeper链接
     */
    private ZooKeeper connectServer() {
        ZooKeeper zk = null;
        try {
            zk = new ZooKeeper(registryAddress, Constant.ZK_SESSION_TIMEOUT, event -> {
                if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
                    latch.countDown();
                }
            });
            latch.await();
        } catch (IOException | InterruptedException e) {
            logger.error("获取zookeeper链接出错", e);
        }
        return zk;
    }

    /**
     * 添加根节点
     */
    private void addRootNode(ZooKeeper zk){
        try {
            Stat stat = zk.exists(Constant.ZK_REGISTRY_PATH, false);
            if (stat == null) {
                zk.create(Constant.ZK_REGISTRY_PATH, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
        } catch (KeeperException | InterruptedException e) {
            logger.error("添加根节点出错", e);
        }
    }

    /**
     * 创建节点
     */
    private void createNode(ZooKeeper zk, String data) {
        byte[] bytes = data.getBytes();
        try {
            zk.create(Constant.ZK_DATA_PATH, bytes, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        } catch (KeeperException | InterruptedException e) {
            logger.error("创建子节点出错", e);
        }
    }
}
